package org.libcsp.generic.api.response;


import lombok.Getter;
import lombok.ToString;
import org.libcsp.generic.api.enums.E;
import org.libcsp.generic.api.type.Void;

import java.io.Serializable;
import java.util.Collection;
import java.util.Map;

@SuppressWarnings("unused")
@ToString
public class R<T extends IResponse> implements Serializable {
    @Getter
    private final int code;
    @Getter
    private final String msg;
    @Getter
    private final T result;


    public final static R<Void> SUCCESS = new R<>(E.SUCCESS, null);
    public final static R<Void> FAILURE = new R<>(E.FAILURE, null);

    private R(E e, T result) {
        this.code = e.getCode();
        this.msg = e.getMsg();
        this.result = result;
    }
    private R(E e) {
        this.code = e.getCode();
        this.msg = e.getMsg();
        this.result = null;
    }


    public static <T extends IResponse> R<T> success(T result) {
        return new R<>(E.SUCCESS, result);
    }

    public static <T extends IResponse> R<Void> success() {
        return SUCCESS;
    }

    public static <T extends IResponse> R<T> success(E e, T result) {
        return new R<>(e, result);
    }

    public static <T extends IResponse> R<Void> success(E e) {
        return new R<>(e);
    }

    public static <T extends IResponse> R<T> failure(T result) {
        return new R<>(E.FAILURE, result);
    }

    public static <T extends IResponse> R<Void> failure() {
        return FAILURE;
    }

    public static <T extends IResponse> R<T> failure(E e, T result) {
        return new R<>(e, result);
    }

    public static <T extends IResponse> R<Void> failure(E e) {
        return new R<>(e);
    }

    // boolean
    public static <T extends IResponse> R<Void> isTrue(boolean expression) {
        return expression ? success() : failure();
    }

    public static <T extends IResponse> R<? extends IResponse> isTrue(boolean expression, T result) {
        return expression ? success(result) : failure();
    }

    public static <T extends IResponse> R<? extends IResponse> isTrue(boolean expression, E e) {
        return expression ? success() : failure(e);
    }

    public static <T extends IResponse> R<? extends IResponse> isTrue(boolean expression, E e, T result) {
        return expression ? success(result) : failure(e);
    }

    public static <T extends IResponse> R<? extends IResponse> isFalse(boolean expression) {
        return isTrue(!expression);
    }

    public static <T extends IResponse> R<? extends IResponse> isFalse(boolean expression, T result) {
        return isTrue(!expression, result);
    }

    public static <T extends IResponse> R<? extends IResponse> isFalse(boolean expression, E e) {
        return isTrue(!expression, e);
    }

    public static <T extends IResponse> R<? extends IResponse> isFalse(boolean expression, E e, T result) {
        return isTrue(!expression, e, result);
    }

    private static boolean blank(String str) {
        if (str == null) {
            return false;
        }
        return str.trim().isEmpty();
    }

    // String
    public static <T extends IResponse> R<? extends IResponse> isBlank(String str) {
        return isTrue(blank(str));
    }

    public static <T extends IResponse> R<? extends IResponse> isBlank(String str, T result) {
        return isTrue(blank(str), result);
    }

    public static <T extends IResponse> R<? extends IResponse> isBlank(String str, E e) {
        return isTrue(blank(str), e);
    }

    public static <T extends IResponse> R<? extends IResponse> isBlank(String str, E e, T result) {
        return isTrue(blank(str), e, result);
    }

    public static <T extends IResponse> R<? extends IResponse> isNotBlank(String str) {
        return isTrue(!blank(str));
    }

    public static <T extends IResponse> R<? extends IResponse> isNotBlank(String str, T result) {
        return isTrue(!blank(str), result);
    }

    public static <T extends IResponse> R<? extends IResponse> isNotBlank(String str, E e) {
        return isTrue(!blank(str), e);
    }

    public static <T extends IResponse> R<? extends IResponse> isNotBlank(String str, E e, T result) {
        return isTrue(!blank(str), e, result);
    }

    // 集合
    public static <T extends IResponse, Element extends Collection<Element>> R<? extends IResponse> isEmpty(Collection<Element> collection) {
        return isTrue(collection == null || collection.size() == 0);
    }

    public static <T extends IResponse, Element extends Collection<Element>> R<? extends IResponse> isEmpty(Collection<Element> collection, T result) {
        return isTrue(collection == null || collection.size() == 0, result);
    }

    public static <T extends IResponse, Element extends Collection<Element>> R<? extends IResponse> isEmpty(Collection<Element> collection, E e) {
        return isTrue(collection == null || collection.size() == 0, e);
    }

    public static <T extends IResponse, Element extends Collection<Element>> R<? extends IResponse> isEmpty(Collection<Element> collection, E e, T result) {
        return isTrue(collection == null || collection.size() == 0, e, result);
    }

    public static <T extends IResponse, Element extends Collection<Element>> R<? extends IResponse> isNotEmpty(Collection<Element> collection) {
        return isFalse(collection == null || collection.size() == 0);
    }

    public static <T extends IResponse, Element extends Collection<Element>> R<? extends IResponse> isNotEmpty(Collection<Element> collection, T result) {
        return isFalse(collection == null || collection.size() == 0, result);
    }

    public static <T extends IResponse, Element extends Collection<Element>> R<? extends IResponse> isNotEmpty(Collection<Element> collection, E e) {
        return isFalse(collection == null || collection.size() == 0, e);
    }

    public static <T extends IResponse, Element extends Collection<Element>> R<? extends IResponse> isNotEmpty(Collection<Element> collection, E e, T result) {
        return isFalse(collection == null || collection.size() == 0, e, result);
    }

    // 集合元素
    public static <T extends IResponse, Element extends Collection<Element>> R<? extends IResponse> hasElement(Collection<Element> collection, Element element) {
        return isTrue(collection != null && collection.size() > 0 && collection.contains(element));
    }

    public static <T extends IResponse, Element extends Collection<Element>> R<? extends IResponse> hasElement(Collection<Element> collection, Element element, T result) {
        return isTrue(collection != null && collection.size() > 0 && collection.contains(element), result);
    }

    public static <T extends IResponse, Element extends Collection<Element>> R<? extends IResponse> hasElement(Collection<Element> collection, Element element, E e) {
        return isTrue(collection != null && collection.size() > 0 && collection.contains(element), e);
    }

    public static <T extends IResponse, Element extends Collection<Element>> R<? extends IResponse> hasElement(Collection<Element> collection, Element element, E e, T result) {
        return isTrue(collection != null && collection.size() > 0 && collection.contains(element), e, result);
    }

    public static <T extends IResponse, Element extends Collection<Element>> R<? extends IResponse> hasNoElement(Collection<Element> collection, Element element) {
        return isFalse(collection != null && collection.size() > 0 && collection.contains(element));
    }

    public static <T extends IResponse, Element extends Collection<Element>> R<? extends IResponse> hasNoElement(Collection<Element> collection, Element element, T result) {
        return isFalse(collection != null && collection.size() > 0 && collection.contains(element), result);
    }

    public static <T extends IResponse, Element extends Collection<Element>> R<? extends IResponse> hasNoElement(Collection<Element> collection, Element element, E e) {
        return isFalse(collection != null && collection.size() > 0 && collection.contains(element), e);
    }

    public static <T extends IResponse, Element extends Collection<Element>> R<? extends IResponse> hasNoElement(Collection<Element> collection, Element element, E e, T result) {
        return isFalse(collection != null && collection.size() > 0 && collection.contains(element), e, result);
    }


    // map
    public static <T extends IResponse, K extends Map<K, V>, V extends Map<K, V>> R<? extends IResponse> isEmpty(Map<K, V> map) {
        return isTrue(map == null || map.size() == 0);
    }

    public static <T extends IResponse, K extends Map<K, V>, V extends Map<K, V>> R<? extends IResponse> isEmpty(Map<K, V> map, T result) {
        return isTrue(map == null || map.size() == 0, result);
    }

    public static <T extends IResponse, K extends Map<K, V>, V extends Map<K, V>> R<? extends IResponse> isEmpty(Map<K, V> map, E e) {
        return isTrue(map == null || map.size() == 0, e);
    }

    public static <T extends IResponse, K extends Map<K, V>, V extends Map<K, V>> R<? extends IResponse> isEmpty(Map<K, V> map, E e, T result) {
        return isTrue(map == null || map.size() == 0, e, result);
    }

    public static <T extends IResponse, K extends Map<K, V>, V extends Map<K, V>> R<? extends IResponse> isNotEmpty(Map<K, V> map) {
        return isFalse(map == null || map.size() == 0);
    }

    public static <T extends IResponse, K extends Map<K, V>, V extends Map<K, V>> R<? extends IResponse> isNotEmpty(Map<K, V> map, T result) {
        return isFalse(map == null || map.size() == 0, result);
    }

    public static <T extends IResponse, K extends Map<K, V>, V extends Map<K, V>> R<? extends IResponse> isNotEmpty(Map<K, V> map, E e) {
        return isFalse(map == null || map.size() == 0, e);
    }

    public static <T extends IResponse, K extends Map<K, V>, V extends Map<K, V>> R<? extends IResponse> isNotEmpty(Map<K, V> map, E e, T result) {
        return isFalse(map == null || map.size() == 0, e, result);
    }

    public static <T extends IResponse, K extends Map<K, V>, V extends Map<K, V>> R<? extends IResponse> containsKey(Map<K, V> map, K k) {
        return isTrue(map != null && map.size() > 0 && map.containsKey(k));
    }

    public static <T extends IResponse, K extends Map<K, V>, V extends Map<K, V>> R<? extends IResponse> containsKey(Map<K, V> map, K k, T result) {
        return isTrue(map != null && map.size() > 0 && map.containsKey(k), result);
    }

    public static <T extends IResponse, K extends Map<K, V>, V extends Map<K, V>> R<? extends IResponse> containsKey(Map<K, V> map, K k, E e) {
        return isTrue(map != null && map.size() > 0 && map.containsKey(k), e);
    }

    public static <T extends IResponse, K extends Map<K, V>, V extends Map<K, V>> R<? extends IResponse> containsKey(Map<K, V> map, K k, E e, T result) {
        return isTrue(map != null && map.size() > 0 && map.containsKey(k), e, result);
    }

    public static <T extends IResponse, K extends Map<K, V>, V extends Map<K, V>> R<? extends IResponse> notContainsKey(Map<K, V> map, K k) {
        return isFalse(map != null && map.size() > 0 && map.containsKey(k));
    }

    public static <T extends IResponse, K extends Map<K, V>, V extends Map<K, V>> R<? extends IResponse> notContainsKey(Map<K, V> map, K k, T result) {
        return isFalse(map != null && map.size() > 0 && map.containsKey(k), result);
    }

    public static <T extends IResponse, K extends Map<K, V>, V extends Map<K, V>> R<? extends IResponse> notContainsKey(Map<K, V> map, K k, E e) {
        return isFalse(map != null && map.size() > 0 && map.containsKey(k), e);
    }

    public static <T extends IResponse, K extends Map<K, V>, V extends Map<K, V>> R<? extends IResponse> notContainsKey(Map<K, V> map, K k, E e, T result) {
        return isFalse(map != null && map.size() > 0 && map.containsKey(k), e, result);
    }

    // 数组
    public static <T extends IResponse> R<? extends IResponse> isArray(Object o) {
        return R.isTrue(o != null && o.getClass().isArray());
    }

    public static <T extends IResponse> R<? extends IResponse> isArray(Object o, T result) {
        return R.isTrue(o != null && o.getClass().isArray(), result);
    }

    public static <T extends IResponse> R<? extends IResponse> isArray(Object o, E e) {
        return R.isTrue(o != null && o.getClass().isArray(), e);
    }

    public static <T extends IResponse> R<? extends IResponse> isArray(Object o, E e, T result) {
        return R.isTrue(o != null && o.getClass().isArray(), e, result);
    }

    public static <T extends IResponse> R<? extends IResponse> isNotArray(Object o) {
        return R.isFalse(o != null && o.getClass().isArray());
    }

    public static <T extends IResponse> R<? extends IResponse> isNotArray(Object o, T result) {
        return R.isFalse(o != null && o.getClass().isArray(), result);
    }

    public static <T extends IResponse> R<? extends IResponse> isNotArray(Object o, E e) {
        return R.isFalse(o != null && o.getClass().isArray(), e);
    }

    public static <T extends IResponse> R<? extends IResponse> isNotArray(Object o, E e, T result) {
        return R.isFalse(o != null && o.getClass().isArray(), e, result);
    }
}